package com.winning.pmph.filter;

import com.winning.pmph.entity.User;
import com.winning.pmph.service.UserService;
import com.winning.pmph.utils.ApplicationContextUtil;
import com.winning.pmph.utils.KmsHttpServletRequestWrapper;
import com.winning.pmph.utils.MD5Utils;
import com.winning.pmph.utils.PMPHAppUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * @author 吴笛
 */
@WebFilter(filterName = "sessionFilter", urlPatterns = {"/pmph/action/*"})
public class F0SessionFilter implements Filter {
    @SneakyThrows
    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) arg0;
        KmsHttpServletRequestWrapper requestWrapper = new KmsHttpServletRequestWrapper(request);
        HttpServletResponse res = (HttpServletResponse) arg1;
        boolean approved = loginAuthentication(requestWrapper);
        if (approved) {
            boolean ssoFlag = checkSSOFlag(requestWrapper);
            if (isAjaxRequest(requestWrapper)) {
                String loginpage = ssoFlag ? "https://sso.pmph.com/logon/password.jsp" : ApplicationContextUtil.getProperty("login-url");
                res.setHeader("sessionstatus", "timeOut");
                res.setHeader("loginpage", loginpage);
            } else {
                String redirectPath = "<script>window.top.location.href='" + ApplicationContextUtil.getProperty("login-url") + "'</script>";
                if (ssoFlag) {
                    redirectPath = "<script>window.top.location.href='https://sso.pmph.com/logon/password.jsp'</script>";
                }
                PrintWriter writer = res.getWriter();
                writer.write(redirectPath);
                writer.flush();
                writer.close();
            }
            return;
        }
        arg2.doFilter(requestWrapper, arg1);
    }

    @NotNull
    private boolean checkSSOFlag(HttpServletRequest request) {
        if (ArrayUtils.isEmpty(request.getCookies())) {
            return false;
        }
        return Stream.of(request.getCookies())
                .filter(cookie -> StringUtils.equals("sso", cookie.getValue()))
                .findFirst().isPresent();
    }

    /**
     * 检查请求是否需要跳转到登录页面
     * 以下四种情况，任意满足其中一种或多种就不会跳转到登录页面：
     * - 请求中包含token参数，并且通过了token验证
     * - 请求静态资源
     * - 请求访问不受限制的URL
     * - 当前用户已经登录
     *
     * @param req http请求
     * @return true：需要跳转到登录页面，false：不需要跳转到登录页面
     */
    private boolean loginAuthentication(HttpServletRequest req) {
        boolean urlIsNotBlocked = (Arrays.asList("/pmph/action/pmph/login",
                "/pmph/action/pmph/syncUser", "/pmph/action/pmph/checkUser", "/pmph/action/pmph/changePassWord",
                "/pmph/action/file/getFile",
                "/pmph/action/video/play",
                "/pmph/action/audio/play",
                "/pmph/action/increaseQrCode/updateScanCount",
                "/pmph/action/knowledge/selectReleasedKnowledgeDetail").contains(req.getRequestURI())) ||
                req.getRequestURI().contains("/pmph/action/localAction");
        boolean theCurrentUserIsLoggedIn = Objects.nonNull(PMPHAppUtil.getCrtUser());
        boolean tokenVerificationPassed = verifyToken(req);
        return !tokenVerificationPassed && !urlIsNotBlocked && !theCurrentUserIsLoggedIn;
    }

    private boolean verifyToken(HttpServletRequest request) {
        String token = request.getParameter("token");
        String uid = request.getParameter("uid");
        String timestamp = request.getParameter("timestamp");
        if (StringUtils.isBlank(token) || StringUtils.isBlank(uid) || StringUtils.isBlank(timestamp)) {
            return false;
        }
        String privateKey = getPrivateKey(uid);
        String result = MD5Utils.md5(timestamp + privateKey);
        return token.equals(result);
    }

    private String getPrivateKey(String uid) {
        User user = ApplicationContextUtil.getBean(UserService.class).getUserById(uid);
        if (user == null) {
            return "";
        }
        return user.getPassword();
    }

    /**
     * 判断请求是不是ajax请求
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String xRequestedWith = request.getHeader("x-requested-with");
        if (StringUtils.equals(xRequestedWith, "XMLHttpRequest")) {
                return true;
        } else {
            return false;
        }
    }
}
